<template>
  <el-form ref="formRef" :model="formData" :hide-required-asterisk="true" label-width="0">
    <el-table :data="internalData" style="width: 100%" border>
      <el-table-column v-for="column in columns" :key="column.prop" :label="column.label" :width="column.width">
        <template v-slot="scope">
          <el-form-item :label="' '" v-bind="column.formItemProps" :prop="`${column.prop}_${scope.$index}`" >
            <component
              clearable
              :is="renderComponent(column)"
              v-model="internalData[scope.$index][column.prop]"
              v-bind="column.fieldProps || {}"
              v-if="column.editable"
            />
            <span v-else>{{ scope.row[column.prop] }}</span>
          </el-form-item>
        </template>
      </el-table-column>

      <el-table-column fixed="right" v-bind="props.operateColProps" v-if="$slots.operate" label="操作" width="40">
        <template #default="scope">
          <slot name="operate" v-bind="scope"></slot>
        </template>
      </el-table-column>
    </el-table>
  </el-form>
</template>

<script lang="ts" setup>
interface Column {
  prop: string;
  label: string;
  editable?: boolean;
  type?: 'input' | 'select';
  options?: { label: string; value: any }[];
  fieldProps?: {};
  formItemProps?: {};
}

interface Props {
  data: any[];
  columns: Column[];
  operateColProps: any;
  editableKeys: string[];
}

const props = withDefaults(defineProps<Props>(), {
  data: () => [],
  columns: () => [],
  operateColProps: () => ({ width: 100 }),
  editableKeys: () => [],
});

const formRef = ref<FormInstance>();
const internalData = reactive<any[]>([...props.data]);

const formData = computed(() => {
  return internalData.reduce((res, next, i) => {
    const rowEntries = Object.entries(next).reduce((cur, [key, value]) => {
      return (cur[`${key}_${i}`] = value, cur)
    }, {});
    res =  { ...res, ...rowEntries }
    return res
  }, {});
})

const renderComponent = (column: Column) => {
  if (column.type === 'input') return h(ElInput,column.fieldProps||{});
  if (column.type === 'number') return ElInput;
  const { options = [] } = column.fieldProps || {};
  if (column.type === 'select') return h(ElSelect, options?.map?.(option => h(ElOption, { value: option.value, label: option.label || option.text })) );
  return 'span';
};

defineExpose({
  form: formRef,
})

watch(
  () => props.data,
  (newVal) => {
    internalData.splice(0, internalData.length, ...newVal);
  },
  { immediate: true }
);
</script>

<style>

  .el-table--default .cell {
      padding: 0 5px;
  }

  .el-form-item__label {
    padding: 0 0px 0 0;
  }


  .el-form .el-form-item {
    padding-top:0;
    padding-bottom:15px ;
  }

  .el-table--default .el-table__cell {
    /**  padding-top: 5px;**/
      padding-bottom: 0;
  }

</style>
